#include "driver_function.h"

#include "FreeRTOSConfig.h"

/*
 * PA2 ----> TX ----> for printf
 * PA3 ----> RX ----> for receiver file
 *
 * */

uint8_t driver_uart_dma_rx_buf[DRIVER_UART_DMA_LEN] = { 0 };
static void driver_uart_dma_init()
{
    DMA_InitTypeDef  DMA_InitStructure  = {0};

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(DMA1_Channel6); //USART2_RX ----> DMA1_Ch6
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority           = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART2->DATAR);
    DMA_InitStructure.DMA_MemoryBaseAddr     = (u32)driver_uart_dma_rx_buf;
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize         = DRIVER_UART_DMA_LEN;
    DMA_Init(DMA1_Channel6, &DMA_InitStructure);

    DMA_Cmd(DMA1_Channel6, ENABLE);
    USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
}

QueueHandle_t driver_uart_rx_queue;
static void driver_uart_queue_init()
{
    driver_uart_rx_queue = xQueueCreate(DRIVER_UART2_QUEUE_LEN,sizeof(driver_uart_obj));
    configASSERT(driver_uart_rx_queue != NULL);
}

QueueHandle_t driver_uart_get_queue_handle()
{
    return driver_uart_rx_queue;
}

void driver_uart_init(uint32_t baudrate)
{
    GPIO_InitTypeDef  GPIO_InitStructure  = {0};
    USART_InitTypeDef USART_InitStructure = {0};
    NVIC_InitTypeDef  NVIC_InitStructure  = {0};


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate            = baudrate;
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;
    USART_InitStructure.USART_Parity              = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode                = USART_Mode_Tx | USART_Mode_Rx; //send or receiver

    USART_Init(USART2, &USART_InitStructure);
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel                   = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_Cmd(USART2, ENABLE);

    driver_uart_dma_init();

    driver_uart_queue_init();
}


void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USART2_IRQHandler(void)
{
    driver_uart_obj m_driver_uart2;
    strncpy((char*)m_driver_uart2.rx_name, "usart2", sizeof(m_driver_uart2.rx_name) - 1);
    m_driver_uart2.rx_name[sizeof(m_driver_uart2.rx_name) - 1] = '\0';
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    if (USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) {
        DMA_Cmd(DMA1_Channel6, DISABLE);
        m_driver_uart2.rx_len = DRIVER_UART_DMA_LEN - DMA_GetCurrDataCounter(DMA1_Channel6);
        if (m_driver_uart2.rx_len > 0 && m_driver_uart2.rx_len < DRIVER_UART_DMA_LEN)
        memcpy(m_driver_uart2.rx_date,driver_uart_dma_rx_buf,m_driver_uart2.rx_len);
        xQueueSendFromISR(driver_uart_rx_queue,&m_driver_uart2,0);//send recv date
        DMA_SetCurrDataCounter(DMA1_Channel6, DRIVER_UART_DMA_LEN);
        DMA_Cmd(DMA1_Channel6, ENABLE);
        USART_ReceiveData(USART2);
    }
    if (xHigherPriorityTaskWoken) {
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}


